/*
 * Created on Sat Sep 16 2017
 * @flow
 * Copyright (c) 2017 jianglinjie
 */
'use strict';

import NetTask from '../task/NetTask';
import type { NetHandler, ErrorHandleResult } from '../handler/NetHandler';
import type NetRequest from '../request/NetRequest';
import type { NetStrategy } from '../strategy/NetStrategy';

export default class NetClient {
  handlers: Set<NetHandler> = new Set();
  strategy: NetStrategy;

  constructor(strategy: NetStrategy) {
    this.strategy = strategy;
  }

  addHandler(handler: NetHandler): void {
    this.handlers.add(handler);
  }

  removeHandler(handler: NetHandler): void {
    this.handlers.delete(handler);
  }

  async start(request: NetRequest): Promise<any> {
    let finalRequest = await this._createFinalRequest(request);

    try {
      let body = await this._startTask(finalRequest);
      return body;
    } catch (err) {
      let body = await this._handleError(err, request, finalRequest);
      return body;
    }
  }

  async _startTask(request: NetRequest): Promise<any> {
    let task = new NetTask(request, this.strategy);

    let response = await task.start();
    for (let handler of this.handlers) {
      let verifyResult = await handler.verifyResponse(response);

      if (!verifyResult.ok) {
        //不合法的回调
        throw verifyResult.error;
      }
    }

    return response.body;
  }

  //注入公共的header和url参数
  async _createFinalRequest(request: NetRequest): Promise<NetRequest> {
    let extraUrlParam = await this._getExtraUrlParam(request);

    let finalRequest = request.clone();
    finalRequest.urlParam = { ...extraUrlParam, ...finalRequest.urlParam };

    let extraHeaders = await this._getExtraHeaders(finalRequest);
    finalRequest.headers = { ...extraHeaders, ...finalRequest.headers };
    return finalRequest;
  }

  async _getExtraUrlParam(request: NetRequest): Promise<Object> {
    let finalExtraUrlParam = {};

    for (let handler of this.handlers) {

      let extraUrlParam = await handler.injectExtraURLParam(request);

      finalExtraUrlParam = { ...finalExtraUrlParam, ...extraUrlParam };
    }

    return finalExtraUrlParam;
  }

  async _getExtraHeaders(request: NetRequest): Promise<Object> {
    let finalExtraHeaders = {};

    for (let handler of this.handlers) {

      let extraHeaders = await handler.injectExtraHeaders(request);

      finalExtraHeaders = { ...finalExtraHeaders, ...extraHeaders };
    }

    return finalExtraHeaders;
  }

  async _handleError(error: any, orginalRequest: NetRequest, finalRequest: NetRequest): Promise<any> {
    let retry = false;

    for (let handler of this.handlers) {
      let result: ErrorHandleResult = await handler.handleError(error, finalRequest);
      if (result.retry) {
        //只要有一个要求重试 就重试
        retry = true;
      }
    }

    if (retry) {
      let newFinalRequest = await this._createFinalRequest(orginalRequest);
      let body = await this._startTask(newFinalRequest);
      return body;
    } else {
      //不重试 直接抛出错误
      throw error;
    }
  }
}
